package Satellites;

import java.util.Calendar;




public class AuxCalculus {
	
	public static final double raioTerra = 6378.135; //Raio da Terra em metros
	public static final double G = 398600.8; //Aceleracao Gravitica da Terra em m^3/s^2
	public static final double c = Math.pow(3*10,8); //Velocidade da Luz em m/s^2
	public static final double XKE = 0.074366916; 
	private final static double ERROR = 1E-12; //Erro aceitavel para a anomalia real
	private static Calendar cal;
	
	public static double eccentricAnomaly(double e, double M){
		//M = E - e.sin(E) - obter E
		double final_E;
		double E = M;
		final_E = recursiveEccentricAnomaly(M, E, e);
		
		return final_E;
	}
	
	private static double recursiveEccentricAnomaly(double M, double E, double e){
		double E_linha = M + e*Math.sin(E);
		double diff = Math.abs(E_linha - E);
		if (diff < ERROR)
			return E;
		else
			return recursiveEccentricAnomaly(M, E_linha, e);
	}
	
	public int convertDateToEpoch(String year, double timeOfDay){
		int y = Integer.parseInt(year);
		int ano;
		if(y>=57) ano = 1900+y;
		else ano = 2000+y;
		Calendar cal = Calendar.getInstance();
	    cal.set(Calendar.YEAR, ano);
	    cal.set(Calendar.DAY_OF_YEAR, (int) timeOfDay);
		
		return 0;
	}
	
	public static double convertDegreesToRadians(double deg){
  		return Math.toRadians(deg);
  	}
  	public static double convertRadiansToDegrees(double rad){
  		return Math.toDegrees(rad);
  	}
  	
  	public static double convertRevPerDayToRadiansPerMin(double rev){
  		return rev*2*Math.PI/1440;
  	}
  	
    public static double a(double meanMotion){
    	//calculo do semi-eixo maior em metros
    	return Math.pow((XKE/meanMotion),(0.666))*raioTerra;
    }
    
    private static double T_orbit(double meanMotion){
    	//calculo do Torbita em segundos
    	return (2*Math.PI*Math.sqrt(Math.pow(a(meanMotion), 3)/G));
    }
    
    
    public static double n(double meanMotion){
    	return 2*Math.PI/T_orbit(meanMotion);
    }
    
    public static double[] eccentricAnomalyArray(double meanMotion, double meanAnomaly, double eccentricity, int nPoints){
    	double[] meanAnomalyArray = new double[nPoints+1];
    	double[] eccentricAnomalyArray = new double[nPoints+1];
    	double delta = (double) T_orbit(meanMotion)/nPoints;
    	//n
    	double n = n(meanMotion);
    	double aux = 0.0;
    	double M;
    	int i = 0;
    	// calculo da anomalia media e da anomalia excentrica para cada ponto da orbita
    	
    	
    	while(aux < T_orbit(meanMotion)){
    		
    		M = n*aux;
    		meanAnomalyArray[i] = M;
    		
    		eccentricAnomalyArray[i] = AuxCalculus.eccentricAnomaly(eccentricity,M);
    		//System.out.println("i: " + i + " aux: " + aux + "anomalia media: " + meanAnomalyArray[i] + " anomalia excentrica: " + eccentricAnomalyArray[i]);
    		i++;
    		aux+=delta;
    	}
    	
    	return eccentricAnomalyArray;
    }
    
    public static double meanEccentricity(double eccentricity, double meanAnomaly){
    	return AuxCalculus.eccentricAnomaly(eccentricity, meanAnomaly);
    }
	
    public static double dayOfYearNow(){
    	cal = Calendar.getInstance();
    	return (double) cal.get(Calendar.DAY_OF_YEAR) + (double) cal.get(Calendar.HOUR_OF_DAY)/24 + (double) cal.get(Calendar.MINUTE)/1440 + (double) cal.get(Calendar.SECOND)/86400;
    }
    
    public static double dayOfYearIn(double minutes){
    	cal = Calendar.getInstance();
    	return (double) cal.get(Calendar.DAY_OF_YEAR) + (double) cal.get(Calendar.HOUR_OF_DAY)/24 + (double) (cal.get(Calendar.MINUTE)+minutes)/1440 + (double) cal.get(Calendar.SECOND)/86400;
    }
    
    private static double calculateP(double a, double eccentricity){
    	return a*(1-Math.pow(eccentricity, 2));
    }
    
    private static double calculateR(double a, double eccentricity, double meanEccentricity){
    	return a * (1 - eccentricity * Math.cos(meanEccentricity));
    }
    
    private static double calculateTeta(double eccentricity, double eccentricAnomaly, double perigee){
    	return AuxCalculus.convertRadiansToDegrees((2 * Math.atan(Math.sqrt((1+eccentricity)/(1-eccentricity))*Math.tan(eccentricAnomaly/2)) + perigee));
    }
    
    private static double calculateX(double omega, double inclination, double r, double teta){
    	return ( r*Math.cos(teta) ) * Math.cos(-omega) - ( (r*Math.sin(teta)*Math.cos(-inclination)) ) * Math.sin(-omega);
    }
    
    private static double calculateY(double omega, double inclination, double r, double teta){
    	return -(r*Math.cos(teta))*Math.sin(-omega)*((r*Math.sin(teta)*Math.cos(-inclination)))*Math.cos(-omega);
    }

	private static double calculateZ(double teta, double inclination, double r){
		return -(r*Math.sin(teta))*Math.sin(-inclination);
	}
    
    public static Coordinates calculateCartesianCoordinates(double omega, double inclination, double a, double eccentricity, double eccentricAnomaly, double perigee){
    	System.out.println("R: " + calculateR(a, eccentricity, eccentricAnomaly));
    	Coordinates coord = new Coordinates(0.0, 0.0);
    	//X
    	coord.setLong(calculateX(omega, inclination, calculateR(a, eccentricity, eccentricAnomaly), calculateTeta(eccentricity, eccentricAnomaly, perigee)));
    	//Y
    	coord.setLat(calculateY(omega, inclination, calculateR(a, eccentricity, eccentricAnomaly), calculateTeta(eccentricity, eccentricAnomaly, perigee)));
    	//Z
    	coord.setHeight(calculateZ(omega, inclination, calculateR(a, eccentricity, eccentricAnomaly)));
    	return coord;
    }
    
    public static double satSpeed(double a, double eccentricity, double eccentricAnomaly, double omega){
    	// km/h
    	return Math.sqrt((G/calculateP(a, eccentricity)) * (1 + 2 * eccentricity * Math.cos(calculateTeta(eccentricity, eccentricAnomaly, omega))+Math.pow(eccentricity, 2)))*3600;
    }
    
    public static Coordinates convertXYZ2LLH(Coordinates coord){
    	
    	//(LONGITUDE, LATITUDE, ALTITUDE)
    	Coordinates result = new Coordinates(0.0, 0.0);
    	
    	//Longitude
    	if(coord.getLong() >= 0)
    		result.setLong((Math.PI/2) - 2*Math.atan( coord.getLong() / ( Math.sqrt(Math.pow(coord.getLong(), 2)+Math.pow(coord.getLat(), 2) + coord.getLat()) ) ));
    	else
    		result.setLong(-(Math.PI/2) + 2*Math.atan( coord.getLong() / ( Math.sqrt(Math.pow(coord.getLong(), 2)+Math.pow(coord.getLat(), 2) - coord.getLat()) ) ));
    	
    	//Latitude
    	
    	
    	return result;
    }

}
